home *** CD-ROM | disk | FTP | other *** search
- /*
- *----------------------------------------------------------------------------
- *
- * RESTORE.C : a backup restorer for the Atari ST series
- *
- * This code was written to complement the very useful `Turtle'
- * hard disk backup utility. It essentially does a `cp -r', maintaining
- * the time stamps on files. It will create directories as needed
- * on the receiving filesystem.
- *
- * This code is copyright (C) by Ross Alexander, Athabasca University,
- * 1988. It may be freely redistributed and/or modified as long as:
- * 1) This notice appears, &
- * 2) modifications are noted as NOT my work.
- *
- * I think this programme is OK, but I take no responsibility for
- * any result (or lack thereof...) of using it. Caveat Emptor.
- *
- * Basic Algorithm:
- *
- * open source directory
- * count entries, reserve that much memory
- * reopen source directory, read into memory
- * sort alphabetically, moving directories to head
- * of the list.
- * conditionally create target directory
- * call self for all directories in list
- * copy all files in list to target, correcting time stamps
- * release memory for list
- *
- *----------------------------------------------------------------------------
- */
-
- #include <osbind.h>
- #include <stat.h>
- #include <stdio.h>
- #include <ctype.h>
-
- #define CANDIDATES ( S_IJRON | S_IJHID | S_IJSYS | S_IJDIR | S_IJWAC )
- #define NULLPTR ( (char *) 0 )
-
- extern char * malloc();
- extern char * strcpy();
-
- /* this is the stuff at the end of a DMABUFFER */
-
- typedef struct {
- char f_fattr; /* File attributes */
- long f_tandd; /* Time and date words */
- long f_fsize; /* File size */
- char f_fname[14]; /* File name */
- } FILEINFO;
-
- /* this is a big enough buffer to do most files in a gulp */
-
- #define BUFFER_SIZE 16384 /* utterly arbitrary */
- char track_buffer[ BUFFER_SIZE ];
-
- int v_flag = 0; /* verbosity flag */
-
- /*
- *----------------------------------------------------------------------------
- *
- * make a (longer) path name from a path-name and {dir,file}-name components
- *
- *----------------------------------------------------------------------------
- */
-
- char * dircat( path, name )
- char * path;
- char * name;
- {
- int path_len = strlen( path );
- char path_buf[ 128 ]; /* _should_ be lots... */
- char * scan = path_buf;
-
- strcpy( path_buf, path );
- if ( path_len != 0 && path[ path_len - 1 ] != '\\' )
- strcat( path_buf, "\\" );
- strcat( path_buf, name );
-
- while ( * scan ) {
- if ( isupper( * scan ) ) * scan = tolower( * scan );
- ++ scan;
- }
-
- return strcpy( malloc( strlen( path_buf ) + 1 ), path_buf );
- }
-
- /*
- *----------------------------------------------------------------------------
- *
- * count how many entries exist in a directory. ignores volume labels, ., ..
- *
- *----------------------------------------------------------------------------
- */
-
- int get_dir_size( from )
- char * from; /* source pathname */
- {
- DMABUFFER examine; /* place to hold these for counting */
- int status; /* temp to hold Fs{first|next} value*/
- DMABUFFER * old_dta = (DMABUFFER *) Fgetdta();
- char * globname = dircat( from, "*.*" );
- int list_length = 0;
-
- Fsetdta( & examine ); /* read'em here, avoid buss faults! */
- for ( status = Fsfirst( globname, CANDIDATES );
- status == 0;
- status = Fsnext() )
- if ( examine.d_fname[ 0 ] != '.' )
- ++ list_length; /* ignore ., .. */
-
- Fsetdta( old_dta );
- free( globname ); /* don't need this any more */
-
- return list_length;
- }
-
- /*
- *----------------------------------------------------------------------------
- *
- * compare two directory entries; subdirectories sort ahead of files
- *
- *----------------------------------------------------------------------------
- */
-
- static int dir_comp( a, b )
- FILEINFO * a;
- FILEINFO * b;
- {
- int attr_a = a->f_fattr & S_IJDIR;
- int attr_b = b->f_fattr & S_IJDIR;
-
- if ( attr_a != attr_b )
- return attr_a ? -1 : 1; /* directories-ahead-of-files */
- else
- return strcmp( a->f_fname, b->f_fname );
- }
-
- /*
- *----------------------------------------------------------------------------
- *
- * suck in a directory, sort it, return -> entries
- *
- *----------------------------------------------------------------------------
- */
-
- FILEINFO * read_sorted_dir( path, length )
- char * path;
- int length;
- {
- FILEINFO * list = (FILEINFO *) malloc( length * sizeof (FILEINFO) );
- FILEINFO * scan = list;
- char * globname = dircat( path, "*.*" );
- DMABUFFER * old_dta = (DMABUFFER *) Fgetdta();
- DMABUFFER examine;
- int status;
-
- Fsetdta( & examine ); /* read'em here, avoid buss faults! */
- for ( status = Fsfirst( globname, CANDIDATES );
- status == 0;
- status = Fsnext() )
- if ( examine.d_fname[ 0 ] != '.' ) {
- scan->f_fattr = examine.d_fattr;
- scan->f_tandd = examine.d_tandd;
- scan->f_fsize = examine.d_fsize;
- strcpy( scan->f_fname, examine.d_fname );
- ++ scan;
- }
-
- qsort( list, length, sizeof (FILEINFO), dir_comp );
-
- free( globname );
- Fsetdta( old_dta );
-
- return list;
- }
-
- /*
- *----------------------------------------------------------------------------
- *
- * copy a file from `from' to `to_path\to_name', in a careful way.
- *
- *----------------------------------------------------------------------------
- */
-
- char * copy_file( from, to_path, to_name )
- char * from;
- char * to_path;
- char * to_name;
- {
- DMABUFFER * old_dta = (DMABUFFER *) Fgetdta();
- char * to = dircat( to_path, to_name );
- char * tmp = dircat( to_path, "$$$$$$$$.$$$" );
- char * ret_msg = NULLPTR;
-
- struct stat stat_from;
- struct stat stat_to;
-
- int from_h = -1;
- int to_h = -1;
- int dest_exists;
- long chunk;
- int timestamp[ 2 ];
-
- if ( v_flag )
- fprintf( stderr, "\t%s ==> %s\n", from, to );
-
- /* check existence & modes of source */
- if ( stat( from, & stat_from ) == NODEV ) {
- ret_msg = "can't stat source";
- goto exit;
- }
-
- /* check existence & type of destination */
- if ( dest_exists = ( stat( to, & stat_to ) != NODEV ) ) {
- if ( stat_to.st_mtime > stat_from.st_mtime ) {
- ret_msg = "source older than destination";
- goto exit;
- } else if ( ( stat_to.st_mode & S_IJDIR ) != 0 ) {
- ret_msg = "destination is directory";
- goto exit;
- }
- }
-
- /* open source file for reading */
- from_h = Fopen( from, 0 );
- if ( from_h < 0 ) {
- ret_msg = "can't open input file";
- goto exit;
- }
-
- /* create the temporary output file */
- to_h = Fcreate( tmp, stat_from.st_mode );
- if ( to_h < 0 ) {
- ret_msg = "can't create temp file";
- goto exit;
- }
-
- /* copy file contents across */
- Fsetdta( track_buffer );
- while ( stat_from.st_size > 0 ) {
- chunk = stat_from.st_size > BUFFER_SIZE ?
- BUFFER_SIZE : stat_from.st_size;
-
- if ( chunk != Fread( from_h, chunk, track_buffer ) ) {
- ret_msg = "file read error";
- goto exit;
- }
-
- if ( chunk != Fwrite( to_h, chunk, track_buffer ) ) {
- ret_msg = "temp file write error";
- goto exit;
- }
-
- stat_from.st_size -= chunk;
- }
-
- /* close output, delete destination, rename temp to destination */
- Fclose( to_h );
- to_h = -1;
- if ( dest_exists && Fdelete( to ) != 0 ) {
- ret_msg = "can't delete destination";
- goto exit;
- }
-
- if ( Frename( 0, tmp, to ) ) {
- ret_msg = "rename failed";
- goto exit;
- }
-
- /* copy old timestamp to new file */
- to_h = Fopen( to, 1 );
- Fdatime( timestamp, from_h, 0 );
- Fdatime( timestamp, to_h, 1 );
-
- /* sweep up */
- exit:
- if ( from_h >= 0 )
- Fclose( from_h );
- if ( to_h >= 0 )
- Fclose( to_h );
-
- Fsetdta( old_dta );
- free( to );
- free( tmp );
-
- return ret_msg;
- }
-
- /*
- *----------------------------------------------------------------------------
- *
- * drive all the other routines ;-)
- *
- *----------------------------------------------------------------------------
- */
-
- char * cp_hyphen_r( from, to )
- char * from;
- char * to;
- {
- struct stat stat_from;
- struct stat stat_to;
-
- int how_many;
- FILEINFO * list;
- FILEINFO * scan;
-
- char * from_next;
- char * to_next;
- char * t;
-
- if ( v_flag )
- fprintf( stderr, "%s --> %s\n", from, to );
-
- /* guarantee that source exists and is a directory */
- if ( stat( from, & stat_from ) == NODEV
- || ( stat_from.st_mode & S_IJDIR ) == 0 )
- return "source not found or not directory";
-
- /* see if destination exists; if not, try to create it */
- if ( stat( to, & stat_to ) != NODEV ) {
- if ( ( stat_to.st_mode & S_IJDIR ) == 0 )
- return "destination exists & not directory";
- } else
- if ( Dcreate( to ) )
- return "can't create destination directory";
-
- /* now either call self for dir's, or copy files */
- scan =
- list = read_sorted_dir( from, how_many = get_dir_size( from ) );
- while ( scan < list + how_many ) {
- from_next = dircat( from, scan->f_fname );
- to_next = dircat( to, scan->f_fname );
-
- if ( ( scan->f_fattr & S_IJDIR ) != 0 ) {
- if ( ( t = cp_hyphen_r( from_next, to_next ) ) != NULLPTR )
- fprintf( stderr, "%s (%s -> %s)\n", t, from_next, to_next );
- } else
- if ( ( t = copy_file( from_next, to, scan->f_fname ) ) != NULLPTR )
- fprintf( stderr, "%s (%s -> %s)\n", t, from_next, to_next );
-
- free( from_next );
- free( to_next );
- ++ scan;
- }
-
- free( list );
- return NULLPTR;
- }
-
- /* user interface */
-
- main( argc, argv )
- int argc;
- char * * argv;
- {
- char * errmsg;
-
- int c;
- extern int optind;
- extern char * optarg;
-
- while ( ( c = getopt( argc, argv, "v" ) ) != EOF )
- if ( c == 'v' )
- ++ v_flag;
- else
- break;
-
- if ( c != EOF || ( argc - optind ) != 2 ) {
- fprintf( stderr, "%s: usage %s [-v] <src-dir> <dest-dir>\n",
- argv[ 0 ], argv[ 0 ] );
- exit( 1 );
- }
-
- if ( ( errmsg = cp_hyphen_r( argv[ optind ], argv[ optind + 1 ] ) )
- != NULLPTR ) {
- fprintf( stderr, "%s: %s (%s --> %s)\n",
- argv[ 0 ], errmsg, argv[ optind ], argv[ optind + 1 ] );
- exit( 2 );
- }
-
- exit( 0 );
- }
-